package model

import (
	"config-client-v1/init/global"
	j_log "config-client-v1/init/j-log"
	"config-client-v1/utils/tools"
	"encoding/json"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"sync"
)

type WSClient struct {
	Conn           *websocket.Conn    `json:"-"`
	Uid            int                `json:"uid"`
	CreateTime     string             `json:"create_time"`
	LastDataTime   string             `json:"last_data_time"`
	RemoteAddr     string             `json:"remote_addr"`
	Data           chan []*QueueValue `json:"-"`
	AlarmData      chan []*VarAlert   `json:"-"`
	SubscribedAddr map[string]bool    `json:"subscribed_addr"`
	WriteLock      sync.Mutex         `json:"-"`
	CloseSignal    chan uint8         `json:"-"`
}

type WSResponseMessage struct {
	Code int    `json:"code"` // 0.操作成功 1.操作失败 2.推送变量 3. 推送报警 10.推送设备的运行状态
	Msg  string `json:"msg"`
	Data string `json:"data"`
}

type WSRequest struct {
	Type int    `json:"type"` // 01
	Data string `json:"data"` // 参数
}

var WSClientMap *WSClientMapStu
var wsRegister chan *WSClient   // client 注册管道
var wsUnregister chan *WSClient // client 退出管道

func WSRun() {
	WSClientMap = NewWSClientMap()
	wsRegister = make(chan *WSClient, 10000)
	wsUnregister = make(chan *WSClient, 10000)

	addr := global.AppConfig.Section("websocket").Key("addr").String()
	go wsConnManage()
	http.HandleFunc("/echo", echo)
	http.HandleFunc("/importer", importer)
	j_log.LogInfo([]interface{}{"websocket listen on " + addr})
	log.Fatal(http.ListenAndServe(addr, nil))
}

var httpUpGrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func echo(w http.ResponseWriter, r *http.Request) {
	conn, err0 := httpUpGrader.Upgrade(w, r, nil)
	if err0 != nil {
		log.Print("upgrade:", err0)
		return
	}
	client := NewWSClient(conn)
	wsRegister <- client
	go client.Customer()
	go client.handleWSConnect()
}

func (client *WSClient) handleWSConnect() {
	defer func() {
		_ = client.Conn.Close()
		wsUnregister <- client
	}()
	for {
		_, message, err := client.Conn.ReadMessage()
		if err != nil {
			if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
				j_log.LogInfo([]interface{}{client.Conn.RemoteAddr().String(), "用户离线", err.Error()})
			} else {
				j_log.LogError([]interface{}{"conn.ReadMessage error", err.Error()})
			}
			return
		}
		client.LastDataTime = tools.GetNow()
		req := WSRequest{}
		err = json.Unmarshal(message, &req)
		if err != nil {
			_ = client.SendMessage(1, "请求参数解析失败 "+err.Error(), string(message))
			continue
		}
	}
}

// 连接池管理, 检查连接是否在线, 删除离线的client
func wsConnManage() {
	for {
		select {
		case client := <-wsRegister:
			go client.ToNewClientDefaultData()
			existCli, ok := WSClientMap.Get(client.RemoteAddr)
			if ok {
				j_log.LogInfo([]interface{}{client.Conn.RemoteAddr().String(), "客户端复用旧连接"})
				existCli.WriteLock.Lock()
				existCli.Conn = client.Conn
				existCli.LastDataTime = tools.GetNow()
				existCli.WriteLock.Unlock()
			} else {
				WSClientMap.Set(client.RemoteAddr, client)
				j_log.LogInfo([]interface{}{client.Conn.RemoteAddr().String(), "新客户端已连接"})
			}
		case client := <-wsUnregister:
			client.CloseSignal <- 1
			WSClientMap.Delete(client.RemoteAddr)
		}
	}
}
func (client *WSClient) ToNewClientDefaultData() {
	data := make([]*QueueValue, 0)
	now := tools.GetNow()
	VariablesMap.RLock()
	for _, row := range VariablesMap.M {
		data = append(data, &QueueValue{
			Addr:         row.Addr,
			Alert:        "",
			AlertType:    nil,
			CreateTime:   &now,
			FSAlert:      0,
			FSShield:     0,
			Value:        row.Value,
			Fe:           row.Fe,
			FieldName:    row.FieldName,
			Precision:    row.Precision,
			ProjectID:    row.ProjectID,
			RealSpecType: row.RealSpecType,
			SpecType:     row.SpecType,
		})
	}
	VariablesMap.RUnlock()
	jsonB, _ := json.Marshal(&data)
	err := client.SendMessage(2, "success", string(jsonB))
	if err != nil {
		j_log.LogError([]interface{}{"ToNewClientDefaultData 发送消息失败", err.Error()})
	} else {
		j_log.LogInfo([]interface{}{client.RemoteAddr, "已推送默认数据"})
	}
}
func (client *WSClient) Customer() {
	defer func() {
		//VariablesMap.RemoveClientFromAllVariables(client)
	}()
	for {
		select {
		case <-client.CloseSignal:
			//j_log.LogInfo([]interface{}{client.Conn.RemoteAddr().String(), "Customer 协程关闭"})
			return
		case data := <-client.AlarmData:
			b, err := json.Marshal(data)
			if err != nil {
				j_log.LogError([]interface{}{"Customer json编码失败", err.Error()})
				return
			}
			err = client.SendMessage(3, "success", string(b))
			if err != nil {
				j_log.LogError([]interface{}{"Customer 发送消息失败", err.Error()})
				continue
			}
		case data := <-client.Data:
			b, err := json.Marshal(data)
			if err != nil {
				j_log.LogError([]interface{}{"Customer json编码失败", err.Error()})
				return
			}
			err = client.SendMessage(2, "success", string(b))
			if err != nil {
				j_log.LogError([]interface{}{"Customer 发送消息失败", err.Error()})
				continue
			}
		}
	}
}

func (client *WSClient) SendMessage(code int, msg string, data string) (err error) {
	resp := WSResponseMessage{}
	resp.Code = code
	resp.Msg = msg
	resp.Data = data
	jsonB, err := json.Marshal(&resp)
	if err != nil {
		j_log.LogError([]interface{}{"SendMessage json.Marshal ERROR", err.Error()})
		return
	}
	client.WriteLock.Lock()
	defer client.WriteLock.Unlock()
	err = client.Conn.WriteMessage(1, jsonB)
	if err != nil {
		j_log.LogError([]interface{}{"SendMessage WriteMessage ERROR", err.Error()})
		return
	}
	return
}

/*--- WSClientMapStu ---*/

type WSClientMapStu struct {
	M map[string]*WSClient
	sync.RWMutex
}

func (ws *WSClientMapStu) Set(key string, v *WSClient) {
	ws.Lock()
	defer ws.Unlock()
	ws.M[key] = v
	return
}

func (ws *WSClientMapStu) Get(key string) (v *WSClient, ok bool) {
	ws.RLock()
	defer ws.RUnlock()
	v, ok = ws.M[key]
	return
}

func (ws *WSClientMapStu) Delete(key string) {
	ws.Lock()
	defer ws.Unlock()
	delete(ws.M, key)
}

func NewWSClientMap() *WSClientMapStu {
	ws := &WSClientMapStu{}
	ws.M = make(map[string]*WSClient)
	return ws
}

func NewWSClient(conn *websocket.Conn) *WSClient {
	client := WSClient{
		Conn:         conn,
		Uid:          0,
		CreateTime:   tools.GetNow(),
		LastDataTime: tools.GetNow(),
		RemoteAddr:   conn.RemoteAddr().String(),
	}
	client.Data = make(chan []*QueueValue, 100)
	client.AlarmData = make(chan []*VarAlert, 100)
	client.CloseSignal = make(chan uint8, 100)
	client.SubscribedAddr = make(map[string]bool)
	return &client
}

func MakeResponseBytes(t int, data string) (b []byte) {
	return
}

func importer(w http.ResponseWriter, r *http.Request) {
	conn, err0 := httpUpGrader.Upgrade(w, r, nil)
	if err0 != nil {
		log.Print("upgrade:", err0)
		return
	}
	defer conn.Close()
	_, message, err := conn.ReadMessage()
	if err != nil {
		if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
			j_log.LogInfo([]interface{}{conn.RemoteAddr().String(), "用户离线", err.Error()})
		} else {
			j_log.LogError([]interface{}{"conn.ReadMessage error", err.Error()})
		}
		return
	}
	req := WSRequest{}
	err = json.Unmarshal(message, &req)
	if err != nil {
		_ = conn.WriteMessage(1, MakeResponseBytes(1, "请求参数解析失败 "+err.Error()))
		return
	}
	//resp := WSResponseMessage{}
	//resp.Code = 2
	//resp.Msg = ""
	//resp.Data = ""
	//messageBytes, err := json.Marshal(&resp)
	//if err != nil {
	//	j_log.LogError([]interface{}{"SendMessage json.Marshal ERROR", err.Error()})
	//	return
	//}
	//err = conn.WriteMessage(1, messageBytes)
	//if err != nil {
	//	j_log.LogError([]interface{}{"SendMessage WriteMessage ERROR", err.Error()})
	//	return
	//}
}

type EquipRunningState struct {
	EquipType        string `json:"equip_type"`         // 设备类型 fse = 自研设备, ppe = 第三方设备
	EquipID          int    `json:"equip_id"`           // 设备ID , fse_id 或 ppe_id
	RunningState     int    `json:"running_state"`      // 0. 未运行 1. 正在启动 2. 已启动 3. 正在停止 4. 已停止 5. 正在重连
	RunningStateText string `json:"running_state_text"` // 运行状态中文
}

func (ws *WSClientMapStu) BroadCastEquipRunningState(equipType string, equipID int, runningState int) {
	if ws == nil {
		return
	}
	runningStateText := ""
	switch runningState {
	case 0:
		runningStateText = "未运行"
	case 1:
		runningStateText = "正在启动"
	case 2:
		runningStateText = "已启动"
	case 3:
		runningStateText = "正在停止"
	case 4:
		runningStateText = "已停止"
	case 5:
		runningStateText = "正在重连"
	}
	ws.RLock()
	defer ws.RUnlock()
	for _, v := range ws.M {
		equipRunningState := EquipRunningState{}
		equipRunningState.EquipType = equipType
		equipRunningState.EquipID = equipID
		equipRunningState.RunningState = runningState
		equipRunningState.RunningStateText = runningStateText

		message := WSResponseMessage{}
		message.Code = 10
		message.Msg = "设备状态改变"
		jsonB, _ := json.Marshal(&equipRunningState)
		message.Data = string(jsonB)
		jsonB2, _ := json.Marshal(&message)
		v.WriteLock.Lock()
		_ = v.Conn.WriteMessage(1, jsonB2)
		v.WriteLock.Unlock()
	}
}
